18. 四数之和

18. 四数之和

Similar Question

leading to the advanced question

Solution Tips

方案一: 暴力法 + 剪枝

var fourSum = function(nums, target) {
    // 两个 for 循环遍历, j = i + 1, 形成一个二维矩阵, 三角形的矩阵, 矩阵直接记录形成哈希表
    // 二维矩阵内, 的每个元素, 进行搜索, 但是不能是同行或者同列的, 寻找自身的相反数
    // 而且找出的结果中, 四个元素不能相同, 相同的需要去除才行
    const map = {};
    for (let i = 0; i < nums.length; i++) {
        for (let j = i + 1; j < nums.length; j++) {
            let sum = nums[i] + nums[j];
            if (map[sum]) {
                map[sum].push([i, j]);
            }
            else {
                map[sum] = [[i, j]];
            }
        }
    }

    const dirty = [];
    // 找到相反数, 组合后去重, 长度依然为4的才合格
    for (const [key, val] of Object.entries(map)) {
        const positive = map[target-key];
        for (let i = 0; i < val.length; i++) {
            const pairOne = val[i];
            for (let j = 0; j < positive.length; j++) {
                const pairTwo = positive[j];
                const compose = [...new Set([...pairOne, ...pairTwo])]
                if (compose.length === 4) {
                    dirty.push(compose);
                }
            }
        }
    }
    // 对 res 去重, 因为索引一定是有区别的, 所以直接根据和去重即可
    const res = {};
    for (let i = 0; i < dirty.length; i++) {
        const sum = dirty[i].reduce((acc, a) => acc + a, 0);
        if (!res[sum]) {
            res[sum] = dirty[i];
        }
    }
    return Object.values(res).map((indexArr) => indexArr.map(index => nums[index]));
};

// let nums = [1,0,-1,0,-2,2], target = 0
let nums = [2,2,2,2,2], target = 8
console.log(fourSum(nums, target));

这种方法没有办法去重, 去重增加的复杂度太多了

方法二: 排序 + 跳过重复 + 对撞指针

就是三数之和的思路

var fourSum = function(nums, target) {
    // 想办法改成三数之和? 通过等式变化一下位置而已, 还是改变不了本质
    // 参考从两数之和到三数之和, 朴素的增加一层循环吧
    const res = [];
    const n = nums.length;
    nums.sort((a, b) => a - b);

    for (let i = 0; i < n; i++) {
        for (let j = i + 1; j < n; j++) {
            let left = j + 1;
            let right = n - 1;

            while (left < right) {
                const sum = nums[i] + nums[j] + nums[left] + nums[right];

                if (sum === target) {
                    res.push([nums[i], nums[j], nums[left], nums[right]]);
                }

                if (sum <= target) {
                    while (left < right && nums[left] === nums[++left]) {}
                }
                if (sum >= target) {
                    while (left < right && nums[right] === nums[--right]) {}
                }
            }
            while (nums[j] === nums[j + 1]) j++
        }
        while (nums[i] === nums[i + 1]) i++
    }

    return res;
};